home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
forms
/
FORMS
/
chart.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
13KB
|
438 lines
/*
* chart.c
*
* Forms Object class: CHART
*
* Written by: Mark Overmars
*
* Version 2.2 a
* Date: Jun 21, 1993
*/
#include <malloc.h>
#include "gl/gl.h"
#include "gl/device.h"
#include <sys/types.h>
#include <math.h>
#include <string.h>
#include "forms.h"
#define PI 3.14159265
#define ARCINC (2.0*PI/3600.0)
/* Object specific information */
typedef struct{
float val; /* Value of the entry */
char str[16]; /* Label of the entry */
int col; /* Color of the entry */
} ENTRY;
typedef struct{
int numb; /* Number of entries */
int maxnumb; /* Maximal number of entries to display */
ENTRY entries[FL_CHART_MAX+1];/* The entries */
float min,max; /* The boundaries */
int autosize; /* Whether the x-axis should be scaled */
} SPEC;
static void vv(float x, float y)
{ short v[2]; v[0] = (short) x; v[1] = (short) y; v2s(v);}
static void draw_barchart(float x, float y, float w, float h,
int numb, ENTRY entries[],
float min, float max, int autosize, int maxnumb)
/* Draws a bar chart. x,y,w,h is the bounding box, entries the array of
numb entries and min and max the boundaries. */
{
int i;
float bwidth; /* Width of a bar */
float zeroh; /* Height of zero value */
float incr; /* Increment per unit value */
float lh = fl_get_char_height(FL_SMALL_FONT,FL_NORMAL_STYLE);
incr = h/ (max-min);
zeroh = y-min * incr;
if ( -min*incr < lh)
{ incr = (h - lh + min*incr)/(max-min); zeroh = y+lh;}
if (autosize) bwidth = w/numb; else bwidth = w/maxnumb;
/* Draw base line */
fl_color(BLACK);
bgnline(); vv(x,zeroh); vv(x+w,zeroh); endline();
if (min == 0.0 && max == 0.0) return; /* Nothing else to draw */
/* Draw the bars */
for (i=0; i<numb; i++)
fl_rectbound(x+i*bwidth,zeroh,bwidth+1.0, entries[i].val*incr+1.0,
entries[i].col);
/* Draw the labels */
fl_color(BLACK);
for (i=0; i<numb; i++)
fl_drw_text_beside(FL_ALIGN_BOTTOM,x+(i+0.5)*bwidth,zeroh,0.0,0.0,
BLACK,FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str);
}
static void draw_horbarchart(float x, float y, float w, float h,
int numb, ENTRY entries[],
float min, float max, int autosize, int maxnumb)
/* Draws a horizontal bar chart. x,y,w,h is the bounding box, entries the
array of numb entries and min and max the boundaries. */
{
int i;
float bwidth; /* Width of a bar */
float zeroh; /* Position of zero value */
float incr; /* Increment per unit value */
float lw = 0.0; /* Maximal label width */
/* Compute maximal label width */
for (i=0; i<numb; i++)
if (fl_get_string_width(FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str) > lw)
lw = fl_get_string_width(FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str);
if (lw >0.0) lw += 4.0;
incr = w/ (max-min);
zeroh = x-min * incr;
if ( -min*incr < lw)
{ incr = (w - lw + min*incr)/(max-min); zeroh = x+lw;}
if (autosize) bwidth = h/numb; else bwidth = h/maxnumb;
/* Draw base line */
fl_color(BLACK);
bgnline(); vv(zeroh,y); vv(zeroh,y+h); endline();
if (min == 0.0 && max == 0.0) return; /* Nothing else to draw */
/* Draw the bars */
for (i=0; i<numb; i++)
fl_rectbound(zeroh,y+i*bwidth,entries[numb-i-1].val*incr+1.0,bwidth+1.0,
entries[numb-i-1].col);
/* Draw the labels */
fl_color(BLACK);
for (i=0; i<numb; i++)
fl_drw_text_beside(FL_ALIGN_LEFT,zeroh+2.0,y+(i+0.5)*bwidth,0.0,0.0,
BLACK,FL_SMALL_FONT,FL_NORMAL_STYLE,entries[numb-i-1].str);
}
static void draw_linechart(int type, float x, float y, float w, float h,
int numb, ENTRY entries[],
float min, float max, int autosize, int maxnumb)
/* Draws a line chart. x,y,w,h is the bounding box, entries the array of
numb entries and min and max the boundaries. */
{
int i;
float ttt;
float bwidth; /* distance between points */
float zeroh; /* Height of zero value */
float incr; /* Increment per unit value */
float lh = fl_get_char_height(FL_SMALL_FONT,FL_NORMAL_STYLE);
incr = (h-2.0*lh)/ (max-min);
zeroh = y+lh-min * incr;
if (autosize) bwidth = w/numb; else bwidth = w/maxnumb;
/* Draw the values */
for (i=0; i<numb; i++)
{
if (type == FL_SPIKE_CHART)
{
bgnline();
fl_color(entries[i].col);
vv(x+(i+0.5)*bwidth,zeroh);
vv(x+(i+0.5)*bwidth,zeroh+entries[i].val*incr);
endline();
}
else if (type == FL_LINE_CHART && i != 0)
{
bgnline();
fl_color(entries[i-1].col);
vv(x+(i-0.5)*bwidth,zeroh+entries[i-1].val*incr);
vv(x+(i+0.5)*bwidth,zeroh+entries[i].val*incr);
endline();
}
else if (type == FL_FILLED_CHART && i != 0)
{
bgnpolygon();
fl_color(entries[i-1].col);
vv(x+(i-0.5)*bwidth,zeroh);
vv(x+(i-0.5)*bwidth,zeroh+entries[i-1].val*incr);
if ((entries[i-1].val > 0.0 && entries[i].val < 0.0) ||
(entries[i-1].val < 0.0 && entries[i].val > 0.0))
{
ttt = entries[i-1].val / (entries[i-1].val - entries[i].val);
vv(x+(i-0.5+ttt)*bwidth,zeroh);
endpolygon();
bgnpolygon();
vv(x+(i-0.5+ttt)*bwidth,zeroh);
}
vv(x+(i+0.5)*bwidth,zeroh+entries[i].val*incr);
vv(x+(i+0.5)*bwidth,zeroh);
endpolygon();
bgnline();
fl_color(BLACK);
vv(x+(i-0.5)*bwidth,zeroh+entries[i-1].val*incr);
vv(x+(i+0.5)*bwidth,zeroh+entries[i].val*incr);
endline();
}
}
/* Draw base line */
fl_color(BLACK);
bgnline(); vv(x,zeroh); vv(x+w,zeroh); endline();
/* Draw the labels */
fl_color(BLACK);
for (i=0; i<numb; i++)
if (entries[i].val >= 0.0)
fl_drw_text_beside(FL_ALIGN_TOP,x+(i+0.5)*bwidth,
zeroh+entries[i].val*incr,
0.0,0.0,BLACK,FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str);
else
fl_drw_text_beside(FL_ALIGN_BOTTOM,x+(i+0.5)*bwidth,
zeroh+entries[i].val*incr,
0.0,0.0,BLACK,FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str);
}
static void draw_piechart(float x, float y, float w, float h,
int numb, ENTRY entries[], int special)
/* Draws a pie chart. x,y,w,h is the bounding box, entries the array of
numb entries */
{
int i;
float xc,yc,rad; /* center and radius */
float tot; /* sum of values */
float incr; /* increment in angle */
float curang; /* current angle we are drawing */
float xl,yl; /* label position */
float txc,tyc; /* temporary center */
float lh = fl_get_char_height(FL_SMALL_FONT,FL_NORMAL_STYLE);
/* compute center and radius */
xc = x+w/2.0; yc = y+h/2.0;
rad = h/2.0 - lh;
if (special) { yc -= 0.1*rad; rad = 0.9*rad;}
/* compute sum of values */
tot = 0.0;
for (i=0; i<numb; i++)
if (entries[i].val > 0.0) tot += entries[i].val;
if (tot == 0.0) return;
incr = 3600.0/tot;
/* Draw the pie */
curang = 0.0;
for (i=0; i<numb; i++)
if (entries[i].val > 0.0)
{
txc = xc; tyc = yc;
/* Correct for special pies */
if (special && i==0)
{
txc += 0.3*rad*cos(ARCINC*(curang+0.5*incr*entries[i].val));
tyc += 0.3*rad*sin(ARCINC*(curang+0.5*incr*entries[i].val));
}
fl_color(entries[i].col);
arcf(txc,tyc,rad, (int) curang, (int) (curang + incr*entries[i].val));
fl_color(BLACK);
arc(txc,tyc,rad, (int) curang, (int) (curang + incr*entries[i].val));
bgnline();
vv(txc,tyc); vv(txc+rad*cos(ARCINC*curang),tyc+rad*sin(ARCINC*curang));
endline();
curang += 0.5 * incr * entries[i].val;
/* draw the label */
xl = txc + 1.1*rad*cos(ARCINC*curang);
yl = tyc + 1.1*rad*sin(ARCINC*curang);
if (xl < txc)
fl_drw_text_beside(FL_ALIGN_LEFT,xl,yl,0.0,0.0,
BLACK,FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str);
else
fl_drw_text_beside(FL_ALIGN_RIGHT,xl,yl,0.0,0.0,
BLACK,FL_SMALL_FONT,FL_NORMAL_STYLE,entries[i].str);
curang += 0.5 * incr * entries[i].val;
bgnline();
vv(txc,tyc); vv(txc+rad*cos(ARCINC*curang),tyc+rad*sin(ARCINC*curang));
endline();
}
}
static void draw_chart(FL_OBJECT *ob)
/* Draws a chart object */
{
SPEC *sp = ((SPEC *)(ob->spec));
float xx,yy,ww,hh;
float min = sp->min, max = sp->max;
int i;
/* Find bounding box */
xx = ob->x+3.0*FL_CHART_BW;
yy = ob->y+3.0*FL_CHART_BW;
ww = ob->w-6.0*FL_CHART_BW;
hh = ob->h-6.0*FL_CHART_BW;
/* Find bounds */
if (min == max)
{
min = max = 0.0;
for (i=0; i<sp->numb; i++)
{
if (sp->entries[i].val < min) min = sp->entries[i].val;
if (sp->entries[i].val > max) max = sp->entries[i].val;
}
}
/* Do the drawing */
fl_drw_box(ob->boxtype,ob->x,ob->y,ob->w,ob->h,ob->col1,FL_CHART_BW);
switch (ob->type)
{
case FL_BAR_CHART:
draw_barchart(xx,yy,ww,hh, sp->numb, sp->entries, min, max,
sp->autosize, sp->maxnumb);
break;
case FL_HORBAR_CHART:
draw_horbarchart(xx,yy,ww,hh, sp->numb, sp->entries, min, max,
sp->autosize, sp->maxnumb);
break;
case FL_PIE_CHART:
draw_piechart(xx,yy,ww,hh,sp->numb,sp->entries,0);
break;
case FL_SPECIALPIE_CHART:
draw_piechart(xx,yy,ww,hh,sp->numb,sp->entries,1);
break;
default:
draw_linechart(ob->type,xx,yy,ww,hh, sp->numb, sp->entries, min, max,
sp->autosize, sp->maxnumb);
break;
}
fl_drw_text_beside(ob->align,ob->x,ob->y,ob->w,ob->h,
ob->lcol,ob->lsize,ob->lstyle,ob->label);
}
static int handle_chart(FL_OBJECT *ob,int event,float mx,float my,char key)
/* Handles an event, returns whether value has changed. */
{
switch (event)
{
case FL_DRAW:
draw_chart(ob);
return 0;
case FL_FREEMEM:
free(ob->spec);
return 0;
}
return 0;
}
/*------------------------------*/
FL_OBJECT *fl_create_chart(int type,float x,float y,float w,float h,
const char *label)
/* creates an object */
{
FL_OBJECT *ob;
ob = fl_make_object(FL_CHART,type,x,y,w,h,label,handle_chart);
ob->boxtype = FL_CHART_BOXTYPE;
ob->col1 = FL_CHART_COL1;
ob->col2 = FL_CHART_COL1;
ob->align = FL_CHART_ALIGN;
ob->lcol = FL_CHART_LCOL;
ob->active = FALSE;
ob->spec = (int *) fl_malloc(sizeof(SPEC));
((SPEC *)(ob->spec))->numb = 0;
((SPEC *)(ob->spec))->maxnumb = FL_CHART_MAX;
((SPEC *)(ob->spec))->autosize = TRUE;
((SPEC *)(ob->spec))->min = 0.0;
((SPEC *)(ob->spec))->max = 0.0;
return ob;
}
FL_OBJECT *fl_add_chart(int type, float x, float y, float w, float h,
const char *label)
/* Adds an object */
{
FL_OBJECT *ob;
ob = fl_create_chart(type,x,y,w,h,label);
fl_add_object(fl_current_form,ob);
return ob;
}
void fl_clear_chart(FL_OBJECT *ob)
/* Clears the contents of a chart. */
{
((SPEC *)(ob->spec))->numb = 0;
fl_redraw_object(ob);
}
void fl_add_chart_value(FL_OBJECT *ob, float val, char str[], int col)
/* Add an item to the chart. */
{
SPEC *sp = ((SPEC *)(ob->spec));
int i;
/* Shift entries if required */
if (sp->numb == sp->maxnumb)
{
for (i=0; i<sp->numb-1; i++) sp->entries[i] = sp->entries[i+1];
sp->numb--;
}
/* Fill in the new entry */
sp->entries[sp->numb].val = val;
sp->entries[sp->numb].col = col;
strncpy(sp->entries[sp->numb].str,str,16);
sp->entries[sp->numb].str[15] = '\0';
sp->numb++;
fl_redraw_object(ob);
}
void fl_insert_chart_value(FL_OBJECT *ob, int index,
float val, char str[], int col)
/* Inserts an item before index to the chart. */
{
SPEC *sp = ((SPEC *)(ob->spec));
int i;
if (index < 1 || index > sp->numb+1) return;
/* Shift entries */
for (i=sp->numb; i >= index; i--) sp->entries[i] = sp->entries[i-1];
if (sp->numb < sp->maxnumb) sp->numb++;
/* Fill in the new entry */
sp->entries[index-1].val = val;
sp->entries[index-1].col = col;
strncpy(sp->entries[index-1].str,str,16);
sp->entries[index-1].str[15] = '\0';
fl_redraw_object(ob);
}
void fl_replace_chart_value(FL_OBJECT *ob, int index,
float val, char str[], int col)
/* Replaces an item in the chart. */
{
SPEC *sp = ((SPEC *)(ob->spec));
if (index < 1 || index > sp->numb) return;
sp->entries[index-1].val = val;
sp->entries[index-1].col = col;
strncpy(sp->entries[index-1].str,str,16);
sp->entries[index-1].str[15] = '\0';
fl_redraw_object(ob);
}
void fl_set_chart_bounds(FL_OBJECT *ob, float min, float max)
/* Sets the boundaries in the value for the object */
{
((SPEC *)(ob->spec))->min = min;
((SPEC *)(ob->spec))->max = max;
fl_redraw_object(ob);
}
void fl_set_chart_maxnumb(FL_OBJECT *ob, int maxnumb)
/* Sets the maximal number of values displayed in the chart */
{
SPEC *sp = ((SPEC *)(ob->spec));
int i;
/* Fill in the new number */
if (maxnumb < 0) return;
if (maxnumb > FL_CHART_MAX)
sp->maxnumb = FL_CHART_MAX;
else
sp->maxnumb = maxnumb;
/* Shift entries if required */
if (sp->numb > sp->maxnumb)
{
for (i = 0; i<maxnumb; i++)
sp->entries[i] = sp->entries[i+sp->numb-maxnumb];
sp->numb = sp->maxnumb;
fl_redraw_object(ob);
}
}
void fl_set_chart_autosize(FL_OBJECT *ob, int autosize)
/* Sets whether the chart should autosize along the x-axis */
{
((SPEC *)(ob->spec))->autosize = autosize;
fl_redraw_object(ob);
}